home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / eulisp / feel0_89.lha / Feel / Modules / collect.em < prev    next >
Lisp/Scheme  |  1993-07-15  |  12KB  |  436 lines

  1. ;; Eulisp Module
  2. ;; Author: pab
  3. ;; File: collect.em
  4. ;; Date: Tue Jun 29 16:05:59 1993
  5. ;;
  6. ;; Project:
  7. ;; Description: 
  8. ;;  Actually, all jap's work.
  9.  
  10. (defmodule collect
  11.   (init
  12.    extras0
  13.    macros0
  14.    defs
  15.    gens
  16.    telos1
  17.    character
  18.    )
  19.   ()
  20.   
  21.   ;; the basic collection operations
  22.   (export
  23.    accumulate
  24.    accumulate1
  25.    concatenate
  26.    do
  27.    emptyp
  28.    fill
  29.    map
  30.    size
  31.    sequencep 
  32.    collectionp
  33.    )
  34.  
  35.   ;; not primitive, but it would be odd to omit them
  36.   (export
  37.    member
  38.    reverse
  39.    )
  40.  
  41.  
  42.   ;; ones I had to write to make the rest work
  43.   (export
  44.    anyp
  45.    intersection
  46.    )
  47.  
  48.   ;; imports to be re-exported
  49.   (export
  50.    element
  51.    )
  52.   
  53.   ;; predicates
  54.   (defpredicate sequencep <sequence>)
  55.   (defpredicate collectionp <collection>)
  56.   
  57.   ;; converter methods
  58.  
  59.   (defmethod (converter <list>) ((c <collection>))
  60.     ;; converts any kind of collection to a list
  61.     (let ((r ()))
  62.       (labels
  63.        ((loop (s)
  64.           (if (null s)
  65.           r
  66.         (progn (setq r (cons (current-element c s) r))
  67.                (loop (previous-state c s))))))
  68.        (loop (final-state c)))))
  69.  
  70.   (defmethod (converter <string>) ((c <collection>))
  71.     ;; converts a collection of characters to a string
  72.     (let ((r (make-string (size c))))
  73.       (labels
  74.        ((loop (s1 s2)
  75.           (cond
  76.            ((null s1)
  77.         r)
  78.            ((characterp (current-element c s1))
  79.         ((setter current-element) r s2 (current-element c s1))
  80.         (loop (next-state c s1) (next-state r s2)))
  81.            (t
  82.         (error
  83.          (format () "list(character)->string: ~a is not a character"
  84.              (current-element c s1))
  85.          <Internal-Error>)))))
  86.        (loop (initial-state c) (initial-state r)))))
  87.  
  88.   (defmethod (converter <table>) ((c <collection>))
  89.     ;; converts any kind of collection to a table
  90.     (let ((r (make <table>
  91.            'comparator eq
  92.            'hash-function generic-hash)))
  93.       (labels
  94.        ((loop (s)
  95.           (if (null s)
  96.           r
  97.         (progn ((setter element) r (current-key c s) (current-element c s))
  98.                (loop (next-state c s))))))
  99.        (loop (initial-state c)))))
  100.  
  101.   (defmethod (converter <vector>) ((c <collection>))
  102.     ;; converts any kind of collection to a vector
  103.     (let ((r (make-vector (size c))))
  104.       (labels
  105.        ((loop (s1 s2)
  106.           (if (null s1)
  107.           r
  108.         (progn ((setter current-element) r s2 (current-element c s1))
  109.                (loop (next-state c s1) (next-state r s2))))))
  110.        (loop (initial-state c) (initial-state r)))))
  111.  
  112.   ;; default methods for collections
  113.  
  114.   (defmethod key-sequence ((c <collection>))
  115.     ;; returns a list of integers from 0 .. size of c
  116.     (labels
  117.      ((loop (i s)
  118.         (if (null s)
  119.         ()
  120.           (cons i (loop (+ i 1) (next-state c s))))))
  121.      (loop 0 (initial-state c))))
  122.  
  123.   (defmethod emptyp ((c <collection>)) (= 0 (size c)))
  124.  
  125.   (defmethod gf-member (v (c <collection>) f)
  126.     ;; returns t if the application of f to v and an element of c does
  127.     ;; see list.em for a more efficient list method
  128.     (let/cc k
  129.         (gf-do
  130.          (if f
  131.          (lambda (x) (if (f v x) (k t) ()))
  132.            (lambda (x) (if (eql v x) (k t) ())))
  133.          c ())))
  134.  
  135.   (defmethod gf-do (f (c <collection>) cs)
  136.     ;; default method for iterating over several collections
  137.     ;; simultaneously, applying the function f to the appropriate
  138.     ;; combinations of elements and ignoring the result
  139.     (cond
  140.      ((null cs)
  141.       ;; simplest case of only one iterand
  142.       (labels
  143.        ((loop-1 (s)
  144.         (if (null s)
  145.             ()
  146.           (progn (f (current-element c s)) (loop-1 (next-state c s))))))
  147.        (loop-1 (initial-state c))))
  148.      ((null (cdr cs))
  149.       ;; two iterands
  150.       (if (or (not (sequencep c)) (not (sequencep (car cs))))
  151.       (let ((ks (intersection (key-sequence c) (key-sequence (car cs)))))
  152.         ;; one or more is a table therefore have to align keys
  153.         (labels
  154.          ((loop-2 (s c1 c2)
  155.               (if (null s)
  156.               ()
  157.             (progn
  158.               (f (element c1 (current-element ks s))
  159.                  (element c2 (current-element ks s)))
  160.               (loop-2 (next-state ks s) c1 c2)))))
  161.          (loop-2 (initial-state ks) c (car cs))))
  162.     (labels
  163.      ;; only collections with natural order
  164.      ((loop-2 (c1 s1 c2 s2)
  165.           (if (or (null s1) (null s2))
  166.               ()
  167.             (progn
  168.               (f (current-element c1 s1) (current-element c2 s2))
  169.               (loop-2 c1 (next-state c1 s1) c2 (next-state c2 s2))))))
  170.      (loop-2 c (initial-state c) (car cs) (initial-state (car cs))))))
  171.      ((anyp (lambda (x) (not (sequencep x))) (cons c cs))
  172.       ;; more than two iterands
  173.       (let ((ks (apply intersection (map key-sequence (cons c cs)))))
  174.     ;; and at least one is a table so align keys
  175.     (labels
  176.      ((loop-n (s cs)
  177.           (if (null s)
  178.               ()
  179.             (progn
  180.               (apply f
  181.                  (map (lambda (c) (element c (current-element ks s))) cs))
  182.               (loop-n (next-state ks s) cs)))))
  183.      (loop-n (initial-state ks) (cons c cs)))))
  184.      (t
  185.       (labels
  186.        ;; only natural order collections
  187.        ((loop-n (cs ss)
  188.         (if (anyp null ss)
  189.             ()
  190.           (progn
  191.             (apply f (map (lambda (c s) (current-element c s)) cs ss))
  192.             (loop-n cs (map (lambda (c s) (next-state c s)) cs ss))))))
  193.        (loop-n (cons c cs) (map initial-state (cons c cs)))))))
  194.  
  195.   ;; define this here temporarily until PAB does a more efficient
  196.   ;; version elsewhere
  197.  
  198.   (defun compose (f g) (lambda l (f (apply g l))))
  199.  
  200.   (defmethod gf-any (f (c <collection>) cs)
  201.     ;; default method for iterating over several collections testing the
  202.     ;; appropriate combinations of elements using f.  If this once
  203.     ;; returns true, no further elements are processed and t is
  204.     ;; returned.
  205.     (let/cc k
  206.         (apply do
  207.            (compose (lambda (x) (if x (k t) ())) f)
  208.            c cs)))
  209.  
  210.   (defmethod gf-map (f (c <collection>) cs)
  211.     ;; default method for iterating over several collections
  212.     ;; simultaneously, applying the function f to the appropriate
  213.     ;; combinations of elements and saving the result in an object of
  214.     ;; the same class as c, which is returned as the result.
  215.     ;; this map method only works for sequences...see table.em for one
  216.     ;; which works for collections without natural order and list.em for
  217.     ;; a (slightly) more efficient list version
  218.     (let ((r (clone c))
  219.       (i 0))
  220.       (apply do
  221.          (compose (lambda (x) ((setter element) r i x) (setq i (+ i 1))) f)
  222.          c cs)
  223.       r))
  224.  
  225.   (defmethod accumulate (f i (c <collection>))
  226.     ;; accumulates and returns the result of applying f to the initial
  227.     ;; value i and the first element of c, then f to the result of that
  228.     ;; and the second, and so on.
  229.     (labels
  230.      ((loop-1 (a s)
  231.           (if (null s)
  232.           a
  233.         (loop-1 (f a (current-element c s)) (next-state c s)))))
  234.      (loop-1 i (initial-state c))))
  235.  
  236.   (defmethod accumulate1 (f (c <collection>))
  237.     ;; as accumulate except that the first value is used the initial
  238.     ;; value and processing then begins with the second value.
  239.     (labels
  240.      ((loop-1 (a s)
  241.           (if (null s)
  242.           a
  243.         (loop-1 (f a (current-element c s)) (next-state c s)))))
  244.      (let ((s (initial-state c)))
  245.        (if (null s)
  246.        ()
  247.      (loop-1 (current-element c s) (next-state c s))))))
  248.  
  249.   ;; fill notes
  250.   ;; ----------
  251.   ;; (1) replace start and end by a collection whose elements define the
  252.   ;; keys to be updated with v.  Useful for objects with non-integer
  253.   ;; keys, but implies need for ranges for those with integer keys.
  254.   ;; (2) currently does nothing if start..end falls outside range defined
  255.   ;; by 0..size.  Arguably wrong behaviour for stretchy objects (tables).
  256.   ;; fixed by adding a method for <table> in table.em
  257.  
  258.   (defmethod fill ((mc <sequence>) v start end)
  259.     ;; stores v in collection mc, starting at element position start and
  260.     ;; finishing at end.
  261.     (labels
  262.      ((loop (i)
  263.         (if (> i end)
  264.         ()
  265.           (progn ((setter element) mc i v) (loop (+ i 1))))))
  266.      (if (and (<= 0 start) (<= start end) (< end (size mc)))
  267.      (loop start)
  268.        ())))
  269.  
  270.   ;; concatenate notes
  271.   ;; -----------------
  272.   ;; (1) uses wrong key with tables...special case for tables??
  273.   ;; in fact, Dylan only defines this for sequence...on tables it is
  274.   ;; more like a merge, but what to do about "collisions"?
  275.  
  276.   (defmethod gf-concatenate-as (class (c <sequence>) cs)
  277.     ;; concatenates the elements of c and cs creating
  278.     ;; an instance of class
  279.     (let* ((sizes (map size (cons c cs)))
  280.        (r (make-vector (accumulate + 0 sizes)))
  281.        (rs (initial-state r))
  282.        (fillptr 0))
  283.       (do
  284.       (lambda (c l)
  285.         (labels
  286.          ((loop (s)
  287.             (if (null s)
  288.             ()
  289.               (progn
  290.             ((setter current-element) r rs (current-element c s))
  291.             (setq rs (next-state r rs))
  292.             (loop (next-state c s))))))
  293.          (loop (initial-state c))))
  294.       (cons c cs)
  295.     sizes)
  296.       (convert r class)))
  297.  
  298.   (defmethod gf-concatenate ((c <collection>) cs)
  299.     ;; see gf-concatenate-as
  300.     (gf-concatenate-as (class-of c) c cs))
  301.  
  302.   (defmethod reverse ((sequence <sequence>))
  303.     ;; returns a new sequence which has been initialized with the
  304.     ;; elements of the argument sequence in the reverse natural order.
  305.     ;; See also list.em for a more efficient list method.  Works for
  306.     ;; tables but doesn't mean anything...it just makes a copy.
  307.     (let* ((r (shallow-copy sequence))
  308.        (rs (final-state r)))
  309.       (do
  310.       (lambda (x)
  311.         ((setter current-element) r rs x)
  312.         (setq rs (previous-state r rs)))
  313.       sequence)
  314.       r))
  315.  
  316.   (defun intersection (c . cs)
  317.     ;; returns a list whose elements appear in the intersection of the
  318.     ;; collections c and cs.  N-ary case computed by intersection of
  319.     ;; first two, then intersection of subsequent collections with the
  320.     ;; intersection so far.
  321.     (cond
  322.      ((null cs)
  323.       c)
  324.      ((null (cdr cs))
  325.       (accumulate
  326.        (lambda (a x) (if (member x c) (cons x a) a))
  327.        ()
  328.        (car cs)))
  329.      (t
  330.       (accumulate
  331.        (lambda (r ci)
  332.      (accumulate
  333.       (lambda (a x) (if (member x r) (cons x a) a))
  334.       ()
  335.       ci))
  336.        (accumulate
  337.     (lambda (a x) (if (member x c) (cons x a) a))
  338.     ()
  339.     (car cs))
  340.        (cdr cs)))))
  341.   
  342.   ;; Copying protocol
  343.   (defmethod clone ((x <collection>))
  344.     (nyi "Subclass must implement clone"))
  345.  
  346.   (defmethod shallow-copy ((collect <collection>))
  347.     (let ((new (clone collect))
  348.       (state (initial-state collect)))
  349.       (do (lambda (value)
  350.         ((setter current-element) collect state value)
  351.         (setq state (next-state collect state)))
  352.       collect)
  353.       new))
  354.  
  355.   (defmethod deep-copy ((collect <collection>))
  356.     (let ((new (clone collect))
  357.       (state (initial-state collect)))
  358.       (do (lambda (value)
  359.         ((setter current-element) collect state (deep-copy value))
  360.         (setq state (next-state collect state)))
  361.       collect)
  362.       new))
  363.  
  364.   )
  365.  
  366. (setq a '(0 1 2 3 4))
  367. (setq b '#(0 1 2 3))
  368. (setq c "012")
  369. (setq d (make <table> 'comparator = 'hash-function generic-hash))
  370. ((setter element) d 0 'zero)
  371. ((setter element) d 1 'one)
  372.  
  373. (do print a)
  374. (do print b)
  375. (do print c)
  376. (do print d)
  377. (do (lambda (a b) (print (list a b))) a b)
  378. (do (lambda (a b) (print (list a b))) c a)
  379. (do (lambda (a b) (print (list a b))) a d)
  380. (do (lambda (a b) (print (list a b))) d a)
  381. (do (lambda (a b c) (print (list a b c))) a b c)
  382. (do (lambda (a b c d) (print (list a b c d))) a b c d)
  383.  
  384. (defmethod select (f (c <collection>))
  385.   (labels
  386.     ((loop-1 (s)
  387.        (if (null s)
  388.        ()
  389.      (progn
  390.        (f (current-key c s) (current-element c s))
  391.        (loop-1 (next-state c s))))))
  392.     (loop-1 (initial-state c))))
  393.  
  394. (defgeneric accumulate-with-key (f i c))
  395.  
  396. (defmethod accumulate-with-key (f i (c <collection>))
  397.   ;; accumulates and returns the result of applying f to the initial
  398.   ;; value i and the first element of c, then f to the result of that
  399.   ;; and the second, and so on.
  400.   (labels
  401.    ((loop-1 (a s)
  402.       (if (null s)
  403.       a
  404.     (loop-1 (f a (current-key c s) (current-element c s))
  405.         (next-state c s)))))
  406.    (loop-1 i (initial-state c))))
  407.  
  408. (defgeneric copy-sequence (s i j))
  409. (export copy-sequence)
  410.  
  411. (defmethod copy-sequence ((s <sequence>) start end)
  412.   (let/cc k
  413.     (accumulate-with-key
  414.      (lambda (a key value)
  415.        (format t "a, key, value = ~a, ~a, ~a~%" a key value)
  416.        (cond
  417.     ((< key start) a)
  418.     ((<= key end) (cons value a))
  419.     (t (k (reverse a)))))
  420.      ()
  421.      s)))
  422.  
  423. (defmethod fill ((s <sequence>) v start end)
  424.   (let/cc k
  425.     (accumulate-with-key
  426.      (lambda (a key value)
  427.        (format t "a, key, value = ~a, ~a, ~a~%" a key value)
  428.        (cond
  429.     ((< key start) ())
  430.     ((<= key end) ((setter element) s key v))
  431.     (t (k ()))))
  432.      ()
  433.      s)))
  434.  
  435.  
  436.